Skip to content

aead: rework traits API#2427

Closed
newpavlov wants to merge 7 commits into
masterfrom
aead/minimize
Closed

aead: rework traits API#2427
newpavlov wants to merge 7 commits into
masterfrom
aead/minimize

Conversation

@newpavlov

@newpavlov newpavlov commented May 25, 2026

Copy link
Copy Markdown
Member

TODO:

  • Update changelog.
  • Update docs.
  • Test new methods.
  • Migrate implementation crates.

Unresolved questions:

  • Solution for potential incorrect reordering of arguments (nonce, aad, plaintext/ciphertext) with the same type (&[u8]).
  • Should we handle potential fallibility in allocate, extend, and truncate closures?

@newpavlov newpavlov requested a review from tarcieri May 25, 2026 17:09
Comment thread aead/src/lib.rs Outdated
Comment thread aead/src/high_aead.rs Outdated
@newpavlov newpavlov changed the title aead: minimize API surface aead: minimize API surface and add support for variable size nonces May 29, 2026
@newpavlov

This comment was marked as outdated.

@newpavlov newpavlov changed the title aead: minimize API surface and add support for variable size nonces aead: rework traits API May 29, 2026
Comment thread aead/src/tag_pos.rs Outdated
Comment thread aead/src/high_aead.rs Outdated
Comment thread aead/src/lib.rs Outdated
Comment thread aead/src/tag_pos.rs Outdated
@tarcieri

Copy link
Copy Markdown
Member

Overall this doesn't feel like an improvement to me. Several things have changed but I don't think they've changed in ways that make more sense.

@newpavlov

newpavlov commented May 31, 2026

Copy link
Copy Markdown
Member Author

IMO variable nonce support, merging AeadCore and AeadInOut, significantly reducing number of crate features, and making Aead properly dyn-compatible (and potentially implementable by IO-based tokens) make a fair amount of sense.

Comment thread aead/src/utils.rs Outdated
Comment thread aead/src/aead.rs
///
/// # Errors
/// AEAD algorithm implementations may return an error if the plaintext or AAD are too long.
fn encrypt_into_vec(&self, nonce: &[u8], aad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>>;

@newpavlov newpavlov Jun 1, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the Payload type for now. I think we either need a more general solution which would help with other methods as well (e.g. Nonce, Aad, Plaintext, etc. wrappers), or we could just tolerate potential incorrect reorderings of the arguments, which are hopefully somewhat unlikely in modern conditions (with IDEs and stuff).

Comment thread aead/src/lib.rs
) -> Result<()>;
aad: &[u8],
plaintext: &[u8],
allocate: impl FnOnce(usize) -> B,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we handle potential fallibility here and in extend/truncate?

Comment thread aead/src/lib.rs
buffer: &mut dyn Buffer,
aad: &[u8],
buf: &mut B,
extend: impl FnOnce(&mut B, usize),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about using a pass-through API:

fn encrypt_within<B: AsMut<[u8]>>(
    &self,
    nonce: &Nonce<Self>,
    aad: &[u8],
    buf: B,
    extend: impl FnOnce(&mut B, usize),
) -> Result<B> { ... }

But I decided against it since it may be inefficient for some buffer types (e.g. ArrayVec).

Comment thread aead/src/variable.rs Outdated
Comment on lines +7 to +15
/// Functionality of Authenticated Encryption with Associated Data (AEAD) algorithms
/// with variable nonce and tag size support.
///
/// <div class="warning">
/// Some algorithms support very short nonce and tag sizes. Users should exercise extreme caution
/// while using this trait since incorrect handling of nonces and tags may defeat security
/// provided by the algorithm.
/// </div>
pub trait VariableAead: AeadCore {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a purely additive change which could be added and discussed in its own PR

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't understand the supertrait bounds here. It seems like it should be the most flexible, fundamental trait which isn't constrained by knowledge of particular sizes, and support different sizes at runtime.

@newpavlov newpavlov Jun 5, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I wrote above, I am not sure about what would be the best implementation relationships between the traits, so I am open to alternatives. I got to the current solution from the following factors:

  1. Aead should support variable nonces, so it's blanket implementation should be based on VariableAead.
  2. We want to automatically (or at least easily) implement VariableAead if type implements AeadCore.
  3. We do not have specialization in stable Rust.
  4. We want to guide users towards "default" sizes even if they rely on VariableAead and, as discussed above, we are likely to have separate "variable" types in implementation crates.

We could make VariableAead more "fundamental" than AeadCore, but it would look strange from the naming perspective ("core" becomes a mid-level layer) and it would mean that implementing both VariableAead and AeadCore would be slightly more annoying.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VariableAead is more fundamental in that it can do things an AeadCore cannot, namely implement multiple sizes simultaneously.

An AeadCore bound means a type that impls VariableAead will have an associated set of fixed sizes for things like nonces and tags, which isn't a property a type which supports multiple sizes at runtime can have.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also could view VariableAead as an "extension" of AeadCore for additional support of nonce sizes at runtime, but I understand your position. I will try to play with it later.

Am I correct, that you prefer for AeadCore implementers to not implement VariableAead? And that Aead should be implemented in terms of AeadCore and not VariableAead? Note that we can not have two blanket impls without support of mutually exclusive traits in the language.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in cases where there is actually a legitimate need to support multiple nonces and tag sizes at runtime, as with AES-GCM, that it can have a VariableAead core which is untyped in regard to nonce and tag sizes, and separately have well-typed wrappers which are newtypes composed in terms of the VariableAead core and delegate to that implementation, rather than using a blanket impl.

The only way such a blanket impl could even work, IMO, is if you kept AeadCore as-is where it only provides the size information, and the blanket impl could use that size information to provide a well-typed API. But I think that makes less sense than just having those types impl the relevant traits directly with a blanket impl that goes the other direction, providing VariableAead for AeadCore implementations.

@tarcieri

tarcieri commented Jun 5, 2026

Copy link
Copy Markdown
Member

I really think, at the very least, this should be broken down into multiple, smaller PRs.

You are trying to rush through a large number of unrelated changes in a single PR shortly before a release.

I would like to see at least two PRs:

  1. A purely additive PR for VariableAead
  2. At least one separate PR for all of the assorted other unrelated changes, which can build on top of the VariableAead PR

Trying to make this many changes so very late in the crate's development lifecycle right before a stable release is highly problematic, IMO, and having them all in a single PR means discussion is unfocused as we're jumping around between all of the different changes rather than focusing on a set of them in isolation.

@newpavlov

Copy link
Copy Markdown
Member Author

Ok, I will remove VariableAead and will add it in a separate PR. But the AeadCore and Aead changes are interconnected and I don't think it makes sense to split them, especially considering that Aead is used by the dev module. The resulting code is pretty small (just 12 methods), so splitting it further would be just a confusing busywork.

@tarcieri

tarcieri commented Jun 5, 2026

Copy link
Copy Markdown
Member

Can we start with VariableAead? It was the whole impetus for making any last minute changes whatsoever.

@newpavlov

Copy link
Copy Markdown
Member Author

I would strongly prefer to start with the AeadCore and Aead changes and to build VaraibleAead on top of it.

I will ignore your "last minute" remarks, otherwise the discussion could get pointlessly heated again and we will get nowhere.

@tarcieri

tarcieri commented Jun 5, 2026

Copy link
Copy Markdown
Member

I would strongly prefer to start with the AeadCore and Aead changes and to build VaraibleAead on top of it.

Where are the actual interdependencies which make that preferable?

@newpavlov

Copy link
Copy Markdown
Member Author

The structure of methods. VariableAead effectively mirrors AeadCore by replacing compile-time sizes with run-time equivalents, so it helps to finalize it first without going through a bunch of annoying iterations.

@tarcieri

tarcieri commented Jun 8, 2026

Copy link
Copy Markdown
Member

I will ignore your "last minute" remarks, otherwise the discussion could get pointlessly heated again and we will get nowhere.

I'm just going to close this PR. This is absolutely the last minute and it's ridiculous to claim it's not. I will contact you on PM.

There are many people including myself who have been waiting on this release. The last stable release was over three years ago.

I do not think it makes sense to make massive numbers of changes in an unfocused PR called "rework traits" at the last minute. That is not a responsible way to develop software.

If you want to make such last minute cross-cutting breaking changes, please open a focused PR that can explain what was wrong with the old API, proposes a change, and can explain how that change is an improvement over the original.

Please do it quickly, people are waiting.

@tarcieri tarcieri closed this Jun 8, 2026
@newpavlov

newpavlov commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

If you want to make such last minute cross-cutting breaking changes, please open a focused PR that can explain what was wrong with the old API, proposes a change, and can explain how that change is an improvement over the original.

IMO calling this PR "unfocused" is frankly ridiculous. I already wrote why I consider this PR improvement. And stop already with the "last minute" card, I tried to introduce changes to the crate a number of times, but you stubbornly refused them using the flimsy "late stage of development" justification despite me incorporating almost all changes requested by you. Sorry, but I do not want to jump through any more unnecessary hoops. I already wasted a lot of time working on the PRs.

As I wrote in PM, feel free to release the crate in any form you deem appropriate. But I will be introducing this and other changes (e.g. support for AE and incremental AEAD) in a future release (probably shortly after) and I will not wait on your feedback with them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants